Skip to content

Conversation

@ArnaudBarre
Copy link
Owner

@ArnaudBarre ArnaudBarre commented Jan 2, 2026

Fixes #2

Rules can now implement an aggregate function that will be called once for all files that have been linted. This allows to implement rules that require cross-file analysis, like detecting circular dependencies.

import { type AST, core, defineConfig } from "tsl";

type ImportsData = {
  imports: { path: string; node: AST.ImportDeclaration }[];
};

export default defineConfig({
  rules: [
    ...core.all(),
    {
      name: "org/noCircularDependencies",
      createData: (): ImportsData => ({ imports: [] }),
      visitor: {
        ImportDeclaration(context, node) {
          context.data.imports.push({ path: toAbsolutePath(node), node });
        },
      },
      aggregate(context, files) {
        //                ^ { sourceFile: AST.SourceFile; data: ImportsData }[]
        for (const circularEntry of getCircularDependencies(files)) {
          context.report({
            message: "Circular dependency detected",
            sourceFile: circularEntry.sourceFile,
            node: circularEntry.data.imports[circularEntry.importIndex].node,
          });
        }
      },
    },
  ],
});

enableProjectWideRulesInIDE is an experimental new option to enable project-wide reports in the IDE (default to false). The IDE implementation is still a work in progress, and memory leaks or performance issues may occur.

core/unusedExport is a new project-wide rule available with this release.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces experimental support for project-wide rules that can analyze multiple files together, enabling cross-file analysis such as detecting circular dependencies or unused exports. The implementation adds an optional aggregate function to the rule interface, which is called after all files have been linted with aggregated data from each file.

Key changes:

  • Added aggregate function support to rule definitions for cross-file analysis
  • Implemented core/unusedExport rule to detect unused exports across the project
  • Added enableProjectWideRulesInIDE experimental config option for IDE integration

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
src/types.ts Added aggregate function signature to Rule type, new AggregateContext and ReportDescriptorWithSourceFile types, and enableProjectWideRulesInIDE config option
src/rules/unusedExport/unusedExport.ts New rule implementation that tracks exports and imports across files to detect unused exports
src/rules/unusedExport/unusedExport.test.ts Test cases for the unusedExport rule covering various export/import scenarios
src/initRules.ts Core engine updates to support aggregate phase, track files for aggregation, handle ignore comments for aggregate reports, and fix line number calculations
src/getPlugin.ts IDE plugin integration for project-wide rules with caching and status tracking
src/cli.ts CLI integration to call aggregate and report results
src/ruleTester.ts Enhanced test framework to support multi-file test cases and aggregate testing
src/rules/noUnnecessaryCondition/noUnnecessaryCondition.ts Removed unnecessary export keywords from internal helper functions
src/rules/noMisusedPromises/noMisusedPromises.ts Removed unnecessary export keywords from internal helper functions
src/rules/_utils/getOperatorPrecedence.ts Removed unnecessary export keyword from internal helper function
src/loadConfig.ts Removed unnecessary export keyword from internal helper function
src/formatDiagnostic.ts Removed unnecessary export keyword from internal helper function
src/index.ts Added unusedExport to exported rules and added ignore comment for self-reference
README.md Added documentation for project-wide rules and enableProjectWideRulesInIDE option
CHANGELOG.md Added release notes for version 1.1.0 with project-wide rules feature

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +79 to +85
const aggregateStatusByProgram = new WeakMap<
Program,
{ count: number; lintedFiles: Set<string> }
>();
const aggregateResultsByProgram = new WeakMap<
Program,
Map<ts.SourceFile, Report[]>
>();
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Memory leak potential: The WeakMaps aggregateStatusByProgram and aggregateResultsByProgram will accumulate entries as Programs are created and destroyed during IDE usage. While WeakMaps should allow garbage collection when Programs are no longer referenced, the aggregate results themselves contain references to SourceFiles and AST nodes which could prevent garbage collection. Consider implementing a mechanism to periodically clear these caches or limit their size, especially given the experimental warning about memory leaks in the config option documentation.

Copilot uses AI. Check for mistakes.
@ArnaudBarre ArnaudBarre marked this pull request as draft January 5, 2026 01:39
@ArnaudBarre
Copy link
Owner Author

This first iteration makes it really complex to have a good editor experience.
Using the languageService should be enough for the first 'multi-files' rules I want to do, I will revisit this later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Multi files rules

2 participants